package etf.hibernate;

import java.util.List;
import java.util.Random;

import etf.library.*;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class ComplexHibernate {
	SessionFactory sessions;
	Session session;
	Transaction tx;

	public ComplexHibernate() {
		// Create SessionFactory and Session object
		sessions = new Configuration().configure().buildSessionFactory();
		session = sessions.openSession();
		tx = null;
	}
		
	public long insert(int size) {
		long elapsedTime = 0;
		try {
			tx = session.beginTransaction();

			long startTime = System.currentTimeMillis();
			for (int i = 0; i < size/100; i++) {
				Address address = new Address("Splitska_"+i, i, "Sarajevo", i, "BiH");
				Library lib = new Library("Biblioteka_"+i, "033-120-240", "lib@lib.ba", address);
				Author author = new Author("Peter_"+i, "Lacko", "Male",i);
				Category cat = new Category("Category_"+i);
				
				for (int j = 0; j < 100; j++) {
					Member m = new Member("John_"+j, "Johns",i,"member@lib.ba");
					Book book = new Book("Book_"+j, j, cat, author);
					Employee emp = new Employee("Jane_"+j, "Janis", j, j, address);
					lib.hireAnEmployee(emp);
					lib.registerAMember(m);
					lib.addABook(book);
					m.rentABook(book);
					m.setLibrary(lib);
				}
				session.save(lib);
				if (i%100==0) {
					session.flush();
					session.clear();
				}
				
			}
			
			tx.commit();
			
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}
		return elapsedTime;
	}
	
	/*
	 *   QUERY ONE
	 */
	public long queryOne(int size) {
		long elapsedTime = 0;
		String hqlQuery = "select b from Book as b join b.renters as m " +
				"where m.phoneNumber = :p " +
				"and b.year = :q " +
				"and b.category.categoryName = :r";
		double suma = 0;
		try {
			
			for (int i = 0; i <4; i++) {
				long startTime = System.currentTimeMillis();
				Query query = session.createQuery(hqlQuery);
				int parameter = getRandom(size / 100);
				query.setInteger("p", parameter);
				query.setInteger("q", getRandom(100));
				query.setString("r", "Category_" + parameter);
				List<Book> result = query.list();
				if (result.size() > 0) {
					Book b = result.get(0);
					System.out.println("hib:" + b.getTitle());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (HibernateException e) {
			e.printStackTrace();
		}
		return (long)suma;
	}
	
	/*
	 *   QUERY TWO
	 */
	public long queryTwo(int size) {
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b " +
				"where b.year = :q " +
				"and b.category.categoryName = :r";
		double suma = 0;
		try {
		
			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				Query query = session.createQuery(hqlQuery);
				query.setInteger("q", getRandom(100));
				query.setString("r", "Category_" + getRandom(size / 100));
				List<Member> result = query.list();
				if (result.size() > 0) {
					Member m = result.get(0);
					System.out.println("hib:" + m.getFirstName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (HibernateException e) {
			e.printStackTrace();
		}
		return (long)suma;
	}
	
	/*
	 *   QUERY THREE
	 */
	public long queryThree(int size) {
		long elapsedTime = 0;
		String hqlQuery = "select l from Library as l " +
				"join l.books as b " +
				"join l.employees as e " +
				"join l.members as m " +
				"where m.phoneNumber = :q " +
				"and b.category.categoryName = :r " +
				"and l.address.houseNumber = :s " +
				"and e.salary = :p " +
				"and b.year = :t " +
				"and m.firstName = :u ";
		double suma = 0;
		try {

			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				int parameter = getRandom(size / 100);
				Query query = session.createQuery(hqlQuery);
				query.setInteger("p", getRandom(100));
				query.setInteger("q", parameter);
				query.setString("r", "Category_" + parameter);
				query.setInteger("s", parameter);
				query.setInteger("t", getRandom(100));
				query.setString("u", "John_" + getRandom(100));
				List<Library> result = query.list();
				if (result.size() > 0) {
					Library l = result.get(0);
					System.out.println("hib:" + l.getLibraryName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (HibernateException e) {
			e.printStackTrace();
		}
		return (long)suma;
	}
	
	/*
	 *   QUERY FOUR
	 */
	public long queryFour(int size) {
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b " +
				"where m.phoneNumber = :q " +
				"and b.category.categoryName = :r " +
				"and b.author.age = :p " +
				"and m.library.address.houseNumber = :s " +
				"and b.year = :t";
		double suma = 0;
		try {
			
			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				int parameter = getRandom(size / 100);
				Query query = session.createQuery(hqlQuery);
				query.setInteger("p", parameter);
				query.setInteger("q", parameter);
				query.setString("r", "Category_" + parameter);
				query.setInteger("s", parameter);
				query.setInteger("t", getRandom(100));
				List<Member> result = query.list();
				if (result.size() > 0) {
					Member m = result.get(0);
					System.out.println("hib:" + m.getFirstName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (HibernateException e) {
			e.printStackTrace();
		}
		return (long)suma;
	}
	
	/*
	 *   UPDATE
	 */
	public long update(int size) {
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b " +
				"where m.phoneNumber = :q " +
				"and b.category.categoryName = :r " +
				"and b.author.age = :p " +
				"and m.library.address.houseNumber = :s " +
				"and b.year = :t";
		try {
			

			long startTime = System.currentTimeMillis();
			
			tx = session.beginTransaction();
			int parameter = getRandom(size/100);
			Query query = session.createQuery(hqlQuery);
			query.setInteger("p", parameter);
			query.setInteger("q", parameter);
			query.setString("r", "Category_" + parameter);
			query.setInteger("s", parameter);
			query.setInteger("t", getRandom(100));

			List<Member> result = query.list();
			if (result.size()>0){
				Member m =  result.get(0);
				m.setFirstName("New_Name");
				session.save(m);
				session.flush();
				System.out.println("hib:" + m.getFirstName());
			}
			
			
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}
		return elapsedTime;
	}
	
	public void deleteFrom(String className){
		try {
			tx = session.beginTransaction();
			String hql = "delete from " + className;
			Query query = session.createQuery(hql);
			query.executeUpdate();
			tx.commit();
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
	}
	
	public void clearDB(){
		deleteFrom("Library");
		deleteFrom("Employee");
		deleteFrom("Book");
		deleteFrom("Category");
		deleteFrom("Author");
		deleteFrom("Address");
		
	}
	
	private int getRandom(int max){
		Random r = new Random();
        return r.nextInt(max); 
	}
	
	public void closeDatabase(){
		session.close();
	}
	
}
